#include "NodeVisitor.h"
#include "TypeCheckDispatcher.h"
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <queue>
#include <vector>

using namespace std;
#ifdef _WIN32
string output_dir = "D:\\CS444\\outputs\\";
#elif defined __unix__
string output_dir = "./output/";
#endif

#define COMMENTLINE (*context_file_out) << ";---------------------------------" << endl;
#define TABBEDPREFIX (*context_file_out) << "\t" 
#define NOPREFIX (*context_file_out)
#define MOVE(TO, FROM) TABBEDPREFIX << "mov\t\tdword " << TO << ",\tdword " << FROM << endl;
#define PUSH(FROM) TABBEDPREFIX << "push\t" << FROM << endl;
#define POP(INTO) TABBEDPREFIX << "pop\t\t" << INTO << endl;
#define DATASECTION NOPREFIX << "section .data" << endl;
#define TEXTSECTION NOPREFIX << "section .text" << endl;
#define THIS "[ebp+8]"
#define ADD(DST, AMOUNT) TABBEDPREFIX << "add\t\t" << DST << ",\t" << AMOUNT << endl;
#define THROWEXCEPTION TABBEDPREFIX << "call\t__exception" << endl;
#define COMPARE(L, R) TABBEDPREFIX << "cmp\tdword " << L << ",\tdword " R << endl;


CodeGeneratingVisitor::CodeGeneratingVisitor(IndexVisitor &i) : NodeVisitor(Post), return_to_parent(false), start_file_out((output_dir + "Start.s").c_str()), class_sizes(i.class_sizes), global_labels(i.global_labels), start_method(i.start_method), error(false) {
	global_labels.insert("__malloc");
	global_labels.insert("__debexit");
	global_labels.insert("__exception");
}

void CodeGeneratingVisitor::visit(RootNode *n) {
	if (!start_method) {
		error = true;
		return;
	}

	context_file_out = &start_file_out;

	//Building the subclassing tables
	vector<ClassDeclarationNode*> class_bucket;
	for (vector<SP<ParseNode> >::iterator unit = n->children.begin(); unit != n->children.end(); ++unit) {
		CompilationUnitNode *cun = (CompilationUnitNode*)(*unit)();
		class_bucket.push_back((ClassDeclarationNode*)(*cun)[0]());
	}

	for (vector<ClassDeclarationNode*>::iterator c1 = class_bucket.begin(); c1 != class_bucket.end(); ++c1) {
		TypeMetaReference t1((*c1)->type_meta.category, (*c1)->type_meta.reference, 0x0);

		for (vector<ClassDeclarationNode*>::iterator c2 = class_bucket.begin(); c2 != class_bucket.end(); ++c2) {
			TypeMetaReference t2((*c2)->type_meta.category, (*c2)->type_meta.reference, 0x0);

			//Use the typechecker to try to cast c2 to c1. If not error, then they can. Else, nope
			subtype_mapping[*c1][*c2] = ITypeCheckDispatcher::ResolveType(ITypeCheckDispatcher::Assignment, t2, t1).category != TypeMeta::Error;
		}
	}
	context_file_out = &start_file_out;


	DATASECTION

	TABBEDPREFIX << "global _start" << endl;
	TABBEDPREFIX << "extern " << *global_labels.begin();
	for (set<string>::iterator label = global_labels.begin()++; label != global_labels.end(); ++label)
		start_file_out << ", " << *label;
	TABBEDPREFIX << endl;


	TEXTSECTION
		NOPREFIX << "_start:" << endl;

	n->CascadeAccept(this);
	return_to_parent = true;

	context_file_out = &start_file_out;
	TABBEDPREFIX << "call " << start_method->label << endl;

	MOVE("ebx", "eax")
		MOVE("eax", "1")
		TABBEDPREFIX << "int 0x80" << endl;
}

void CodeGeneratingVisitor::visit(ClassDeclarationNode *n) {

	if (class_file_out.is_open()) class_file_out.close();

	//Generate a file to output to
	stringstream filename_stream;
	filename_stream << n->identifier << n->index << ".s";

	class_file_out.open((output_dir + filename_stream.str()).c_str());
	context_file_out = &class_file_out;

	DATASECTION;

	set<string> class_global_labels;
	class_global_labels.insert(n->label);

	//Allow others to see the label to this class
	TABBEDPREFIX << "global " << n->label;

	//Create the class data
	{

		set<TypedNode*, compare_decls> methods = n->elements_in_scope[DeclarationNode::Method];
		//Initialise the strings to build the virtual table from
		unsigned int table_size = methods.size();
		vector<string> method_data_regions(table_size, "0");

		vector<string> method_labels_needing_to_be_global;
		//For each declared method in this class,...
		for (set<TypedNode*, compare_decls>::iterator method = methods.begin(); method != methods.end(); ++method) {
			TypedNode *m = *method;
			if (m->label == n->label + "." + m->identifier) {
				class_global_labels.insert(m->label);
				NOPREFIX << ", " << m->label;
			}

			method_data_regions[m->index] = m->label;
		}

		//Build field labels and add them to the global label exposing
		set<TypedNode*, compare_decls> fields = n->elements_in_scope[DeclarationNode::Expression];
		for (set<TypedNode*, compare_decls>::iterator field = fields.begin(); field != fields.end(); ++field) {
			if (!((*field)->modifier & ModifiedNode::Static)) continue;
			TypedNode *f = *field;
			NOPREFIX << ", " << f->label;
			class_global_labels.insert(f->label);
		}

		string appendage = "";
		TABBEDPREFIX << endl << "\textern ";
		for (set<string>::iterator label = global_labels.begin(); label != global_labels.end(); ++label) {
			if (class_global_labels.find(*label) == class_global_labels.end()) {
				NOPREFIX << appendage << *label;
				appendage = ", ";
			}
		}

		NOPREFIX << endl << "" << endl;

		NOPREFIX << ";1 -> This class can be assigned to something of that type" << endl;

		map<ClassDeclarationNode*, bool> &subtypes = subtype_mapping[n];
		vector<string> table_items(subtypes.size());
		for (map<ClassDeclarationNode*, bool>::iterator subtype = subtypes.begin(); subtype != subtypes.end(); ++subtype) {
			if (subtype->first == 0x0) continue;
			table_items[subtypes.size() - subtype->first->index - 1] = (subtype->second ? "DD\t1; " : "DD\t0; ") + subtype->first->package_name + subtype->first->identifier;
		}
		unsigned int pos = 0;
		for (vector<string>::iterator s = table_items.begin(); s != table_items.end(); ++s) {
			TABBEDPREFIX << *s << " (-" << (table_items.size() - ++pos + 2) * 4 << ")" << endl;
		}

		//Put the "can subtype to array" last
		TABBEDPREFIX << "DD " << n->index << "; Class Tag (-4)" << endl;


		NOPREFIX << n->label << ":" << endl;


		for (vector<string>::iterator method_pointer = method_data_regions.begin(); method_pointer < method_data_regions.end(); ++method_pointer)
			TABBEDPREFIX << "DD " << *method_pointer << endl;

		for (set<TypedNode*, compare_decls>::iterator field = fields.begin(); field != fields.end(); ++field) {
			if (!((*field)->modifier & ModifiedNode::Static)) continue;
			NOPREFIX << (*field)->label << "\tDD 0" << endl;
		}

	}

	NOPREFIX << endl;

	TEXTSECTION;

	NOPREFIX << "__instance.initializer:" << endl;
	// prologue
	PUSH("ebp")
		MOVE("ebp", "esp")
		set<TypedNode*, compare_decls> fields = n->elements_in_scope[DeclarationNode::Expression];
	for (set<TypedNode*, compare_decls>::iterator field = fields.begin(); field != fields.end(); ++field) {
		bool field_is_static = ((*field)->modifier & ModifiedNode::Static) != 0x0;
		if (field_is_static) context_file_out = &start_file_out;
		else context_file_out = &class_file_out;

		ExpressionNode *e = (ExpressionNode*)(**field)["Expression"];
		if (!e) continue;

		e->Accept(this);

		string error = CreateLabelWithBase("error"), success = CreateLabelWithBase("success");
		if ((**field).type_meta.category & TypeMeta::Array) {
			COMPARE("[eax+4]", "0; Check the array length")
			TABBEDPREFIX << "jl " << error << endl;
		}
		if ((**field).type_meta.category & (TypeMeta::Reference | TypeMeta::String)) {
			MOVE("ebx", "[" << (**field).type_meta.reference->label << "-4]; Get the tag from the left side type")
			MOVE("ecx", "[eax]; Get the class data for this object")
			TABBEDPREFIX << "imul\tdword ebx,\tdword -4" << endl;
			COMPARE("[ecx-8+ebx]", "0")
			TABBEDPREFIX << "je " << error << endl;
		}

		TABBEDPREFIX << "jmp " << success << endl;
		NOPREFIX << error << ":" << endl;
		THROWEXCEPTION
			NOPREFIX << success << ":" << endl;
		if (field_is_static) MOVE("[" << (**field).label << "]", "eax")
		else {
			MOVE("ebx", THIS << "; == 'this'")
				MOVE("[ebx+" << (**field).Offset() << "]", "eax; == " << (**field).identifier)
		}
	}

	context_file_out = &class_file_out;
	//POP stack and return
	MOVE("esp", "ebp")
		POP("ebp")
		TABBEDPREFIX << "ret" << endl;

}

//Everything about fields is already handled
void CodeGeneratingVisitor::visit(FieldDeclarationNode*) { return_to_parent = true; }

string CodeGeneratingVisitor::CreateLabelWithBase(string base) {
	int eating_the_value;
	return CreateLabelWithBase(base, eating_the_value);
}
string CodeGeneratingVisitor::CreateLabelWithBase(string base, int &index) {
	static std::map<std::string, int> label_usage = std::map<std::string, int>();
	stringstream label_stream;
	label_stream << base << (index = label_usage[base]++);

	string label;
	getline(label_stream, label);
	return label;
}


/*
* Method environment creation
*/

void CodeGeneratingVisitor::visit(MethodDeclarationNode* n) {

	context_file_out = &class_file_out;
	if (n->modifier & (ModifiedNode::Abstract | ModifiedNode::Native)) {
		if (n->modifier & ModifiedNode::Abstract) {
			NOPREFIX << endl << n->label << ": nop" << endl;
		}
		return_to_parent = true;
		return;
	}
	// label
	NOPREFIX << endl << n->label << ":" << endl;
	// prologue
	PUSH("ebp")
		MOVE("ebp", "esp")
		// all possible local variables pushed on stack and frame offset logged
		VariableOffestVisitor vov(*context_file_out);
	n->Accept(&vov);

	// create the label for the end of the function. needed for return statements
	curEndLabel = CreateLabelWithBase("__methodEnd");

	// process code body and get param indexes
	param_index = n->number_of_parameters;
	n->CascadeAccept(this);
	return_to_parent = true;

	// Return statement target
	TABBEDPREFIX << curEndLabel << ": ; METHOD END" << endl;

	//POP stack and return
	MOVE("esp", "ebp")
		POP("ebp")
		TABBEDPREFIX << "ret" << endl;
}

void CodeGeneratingVisitor::visit(ConstructorDeclarationNode* n) {
	context_file_out = &class_file_out;

	// label
	NOPREFIX << endl << n->label << ":" << endl;
	// prologue
	PUSH("ebp")
	MOVE("ebp", "esp")
	// all possible local variables pushed on stack and frame offset logged
	VariableOffestVisitor vov(*context_file_out);
	n->Accept(&vov);

	//get param indexes
	param_index = n->number_of_parameters;

	MOVE("eax", THIS);
	PUSH( "eax ; pass this object");
	//Before we process code body we have to call default constructor of parent
	ClassDeclarationNode* super = n->containing_class->super;
	if (super) {
		TABBEDPREFIX << "; Calling Super's constructor" << endl;


		TypedNode tn;
		tn.identifier = super->identifier + "$";
		TABBEDPREFIX << "call " << (*super->elements_in_scope[DeclarationNode::Method].find(&tn))->label << endl;
	}

	TABBEDPREFIX << "; Initialize fields" << endl;
	TABBEDPREFIX << "call __instance.initializer" << endl;

	POP("eax ; pop 'this' parameter");

	TABBEDPREFIX << "; Constructor Body: " << endl;

	// create the label for the end of the function. needed for return statements
	curEndLabel = CreateLabelWithBase("__constructorEnd");


	// process code body and get param indexes
	param_index = n->number_of_parameters;
	n->CascadeAccept(this);
	return_to_parent = true;

	// Return statement target
	TABBEDPREFIX << curEndLabel << ": ; CONSTRUCTOR END" << endl;

	//POP stack and return
	MOVE("esp", "ebp")
		POP("ebp")
		TABBEDPREFIX << "ret" << endl;
}

void CodeGeneratingVisitor::visit(FormalParameterNode* n) {
	n->index = param_index--;
	n->label = "ebp";
	TABBEDPREFIX << "; parameter:\t" << n->identifier << "\toffset: " << n->Offset() << endl;
}

void VariableOffestVisitor::visit(LocalVariableDeclarationNode* n) {
	n->index = offset++;
	n->label = "ebp";
	file_out << "\t; variable:\t" << n->identifier << "\toffset:\t" << n->Offset() << endl;
	file_out << "\tpush\t0" << endl;
}

void CodeGeneratingVisitor::visit(ReturnStatementNode* n) {
	// evaluate expression and then go to end
	n->CascadeAccept(this);
	return_to_parent = true;

	TABBEDPREFIX << "; RETURNING" << endl;
	TABBEDPREFIX << "jmp	" << curEndLabel << endl;
}


void CodeGeneratingVisitor::visit(ExpressionNode * n){

	n->CascadeAccept(this);

	//class_file_out << ";EXPRESSION" << endl;
	//COMMENTLINE


	return_to_parent = true;


}


/*
Control Flow
*/


void CodeGeneratingVisitor::visit(IfStatementNode *n){

	bool elseStatement = false;

	int numOfChildren = n->children.size();

	if (numOfChildren % 2 == 1){
		numOfChildren -= 1;
		elseStatement = true;
	}

	//number should be even for regular IfStatementNodes

	string nextLabel = CreateLabelWithBase("next"), endLabel = CreateLabelWithBase("end"),
		elseLabel = CreateLabelWithBase("else");

	for (int i = 0; i < numOfChildren; i += 2){

		//if this is the first if
		if (i == 0) TABBEDPREFIX << ";IF START" << endl;

		//if this is an else if, need a target label so above expression can jump to it on false
		else {
			TABBEDPREFIX << ";ELSE IF START" << endl;
			TABBEDPREFIX << nextLabel << ":" << endl;
		}

		string trueLabel = CreateLabelWithBase("true");
		nextLabel = CreateLabelWithBase("next");

		COMMENTLINE
			TABBEDPREFIX << ";EVALUATING CONDITION" << endl;

		//evaluate condition
		(*n)[i]()->Accept(this);
		//eax holds true or false

		COMPARE("eax", "1")
		TABBEDPREFIX << "je		" << trueLabel << endl;

		//on false...
		if (i + 2 != numOfChildren){
			//there's another else if, have to jump to it on false
			TABBEDPREFIX << "jmp		" << nextLabel << endl;
		}
		//if there's an else statement
		else if (elseStatement){
			TABBEDPREFIX << "jmp		" << elseLabel << endl;
		}

		else {
			//otherwise must jump to end and exit if block
			TABBEDPREFIX << "jmp		" << endLabel << endl;
		}

		TABBEDPREFIX << trueLabel << ":" << endl;
		//evaluate the statement
		COMMENTLINE
			TABBEDPREFIX << ";EXECUTING EXPRESSION" << endl;
		(*n)[i + 1]()->Accept(this);
		//jump out of the contol flow block
		TABBEDPREFIX << "jmp	" << endLabel << endl;
		//else branch to next if statement
		TABBEDPREFIX << ";IF END" << endl;

		COMMENTLINE

	}

	if (elseStatement){
		TABBEDPREFIX << ";ELSE START" << endl;
		TABBEDPREFIX << elseLabel << ":" << endl;
		COMMENTLINE
			TABBEDPREFIX << ";EXECUTING EXPRESSION" << endl;
		(*n)[numOfChildren]()->Accept(this);
	}

	//control flow block exit
	TABBEDPREFIX << endLabel << ":" << endl;

	return_to_parent = true;


	COMMENTLINE

}

void CodeGeneratingVisitor::visit(WhileStatementNode * n){

	string endLabel = CreateLabelWithBase("end"), loopLabel = CreateLabelWithBase("loop");

	TABBEDPREFIX << ";WHILE START" << endl;
	TABBEDPREFIX << loopLabel << ":" << endl;
	COMMENTLINE

		TABBEDPREFIX << ";EVALUATING CONDITION" << endl;

	//evaluate condition
	(*n)[0]()->Accept(this);

	//eax holds true or false

	COMPARE("eax", "0")
	//condition is false, jump to end
	TABBEDPREFIX << "je		" << endLabel << endl;

	//otherwise, execute statement and loop to condition evaluation

	COMMENTLINE
		TABBEDPREFIX << ";EXECUTING EXPRESSION" << endl;
	(*n)[1]()->Accept(this);

	TABBEDPREFIX << "jmp		" << loopLabel << endl;

	TABBEDPREFIX << ";WHILE END" << endl;

	TABBEDPREFIX << endLabel << ":" << endl;

	return_to_parent = true;

	COMMENTLINE

}


void CodeGeneratingVisitor::visit(ForStatementNode * n){


	string endLabel = CreateLabelWithBase("end"), loopLabel = CreateLabelWithBase("loop");

	TABBEDPREFIX << ";FOR START" << endl;

	ParseNode* forInit = (*n)["ForInit"];
	ParseNode* forCondition = (*n)["Expression"];
	ParseNode* forUpdate = (*n)["ForUpdate"];
	ParseNode* forStatement = (*n)["Statement"];

	if (forInit){
		COMMENTLINE
			TABBEDPREFIX << ";INITIALIZING LOOP VALUE" << endl;
		forInit->Accept(this);

	}

	TABBEDPREFIX << loopLabel << ":" << endl;

	if (forCondition){

		COMMENTLINE
			TABBEDPREFIX << ";EVALUATING CONDITION" << endl;
		forCondition->Accept(this);

		COMPARE("eax", "0")
		//condition is false, jump to end
		TABBEDPREFIX << "je		" << endLabel << endl;

	}

	//if forCondition is not present or it's true, carry on


	COMMENTLINE
		TABBEDPREFIX << ";EXECUTING EXPRESSION" << endl;
	forStatement->Accept(this);

	if (forUpdate){
		TABBEDPREFIX << ";EXECUTING UPDATE" << endl;
		forUpdate->Accept(this);
	}

	TABBEDPREFIX << "jmp		" << loopLabel << endl;

	TABBEDPREFIX << ";FOR END" << endl;

	TABBEDPREFIX << endLabel << ":" << endl;

	return_to_parent = true;

	COMMENTLINE


}



void CodeGeneratingVisitor::visit(IfThenElseStatementNode * n){

	visit((IfStatementNode*)n);

}


/*
Casts
*/


void CodeGeneratingVisitor::visit(CastExpressionNode* n){
	TABBEDPREFIX << ";CAST" << endl;

	//assuming eax holds lhs

	int castType = n->type_meta.category;

	if (castType == 16){
		TABBEDPREFIX << ";CASTING TO INT" << endl;
		//nothing to be done
	}

	else if (castType == 8){
		TABBEDPREFIX << ";CASTING TO SHORT" << endl;
		TABBEDPREFIX << "sal	eax, 16" << endl;
		TABBEDPREFIX << "sar	eax, 16" << endl;
	}

	else if (castType == 4){
		TABBEDPREFIX << ";CASTING TO BYTE" << endl;
		TABBEDPREFIX << "sal	eax, 24" << endl;
		TABBEDPREFIX << "sar	eax, 24" << endl;
	}

	else if (castType == 2){
		TABBEDPREFIX << ";CASTING TO CHAR" << endl;
		TABBEDPREFIX << "shl	eax, 16" << endl;
		TABBEDPREFIX << "shr	eax, 16" << endl;
	}

	//result is in eax

}


/*
Unary operators
*/

void CodeGeneratingVisitor::visit(UnaryExpressionNode * n){

	TABBEDPREFIX << ";OPERATOR NEGATIVE" << endl;

	(*n)[0]()->Accept(this);
	TABBEDPREFIX << "imul	eax, -1" << endl;
	COMMENTLINE
		return_to_parent = true;

}


/*
Arithmetic operators
*/



void CodeGeneratingVisitor::visit(AdditiveExpressionNode * n){

	string op = ((LeafNode *)(n->children)[1]())->lexeme;

	BinaryOperation_ResolveChildren((*n)[0](), (*n)[2]());

	TABBEDPREFIX << ";OPERATOR: " << op << endl;
	if (op == "+"){
		ADD("eax", "ebx")
	}

	else if (op == "-"){
		TABBEDPREFIX << "sub\teax,\tebx" << endl;

	}

	COMMENTLINE
		return_to_parent = true;
}



void CodeGeneratingVisitor::visit(MultiplicativeExpressionNode * n){

	string op = ((LeafNode *)(n->children)[1]())->lexeme;

	BinaryOperation_ResolveChildren((*n)[0](), (*n)[2]());

	TABBEDPREFIX << ";OPERATOR: " << op << endl;
	if (op == "*"){
		TABBEDPREFIX << "imul	eax, ebx" << endl;
	}

	else if (op == "/") {
		string divide_by_zero = CreateLabelWithBase("dividedbyzero"), success = CreateLabelWithBase("success");
		COMPARE("ebx", "0")
		TABBEDPREFIX << "je " << divide_by_zero << endl;

		TABBEDPREFIX << "cdq					;sign extend eax into edx:eax" << endl;
		TABBEDPREFIX << "idiv	ebx" << endl;

		TABBEDPREFIX << "jmp " << success << endl;
		NOPREFIX << divide_by_zero << ":" << endl;
		THROWEXCEPTION
			NOPREFIX << success << ":" << endl;
	}

	else if (op == "%"){
		TABBEDPREFIX << "cdq					;sign extend eax into edx:eax" << endl;
		TABBEDPREFIX << "idiv	ebx" << endl;
		MOVE("eax", "edx")
	}

	COMMENTLINE
		return_to_parent = true;
}


/*
Comparison Operators
*/

void CodeGeneratingVisitor::visit(RelationalExpressionNode * n){

	string op = ((LeafNode *)(n->children)[1]())->lexeme;

	string trueLabel = CreateLabelWithBase("true"), endLabel = CreateLabelWithBase("end");


	BinaryOperation_ResolveChildren((*n)[0](), (*n)[2]());
	TABBEDPREFIX << ";OPERATOR: " << op << endl;
	COMPARE("eax", "ebx")

	if (op == "<") 	TABBEDPREFIX << "jl		" << trueLabel << endl;
	if (op == "<=") TABBEDPREFIX << "jle	" << trueLabel << endl;
	if (op == ">") 	TABBEDPREFIX << "jg		" << trueLabel << endl;
	if (op == ">=") TABBEDPREFIX << "jge	" << trueLabel << endl;

	MOVE("eax", "0")
		TABBEDPREFIX << "jmp		" << endLabel << endl;
	TABBEDPREFIX << "" << trueLabel << ":" << endl;
	MOVE("eax", "1")
		TABBEDPREFIX << "" << endLabel << ":" << endl;

	COMMENTLINE

		return_to_parent = true;
}



void CodeGeneratingVisitor::visit(EqualityExpressionNode * n){

	string op = ((LeafNode *)(n->children)[1]())->lexeme;

	string trueLabel = CreateLabelWithBase("true"), endLabel = CreateLabelWithBase("end");


	BinaryOperation_ResolveChildren((*n)[0](), (*n)[2]());

	TABBEDPREFIX << ";OPERATOR: " << op << endl;
	COMPARE("eax", "ebx")

	if (op == "==")	TABBEDPREFIX << "je		" << trueLabel << endl;
	if (op == "!=") TABBEDPREFIX << "jne		" << trueLabel << endl;

	MOVE("eax", "0")
		TABBEDPREFIX << "jmp		" << endLabel << endl;
	TABBEDPREFIX << "" << trueLabel << ":" << endl;
	MOVE("eax", "1")
		TABBEDPREFIX << "" << endLabel << ":" << endl;

	COMMENTLINE

		return_to_parent = true;

}

void CodeGeneratingVisitor::visit(ConditionalAndExpressionNode * n){

	string falseLabel = CreateLabelWithBase("false"), endLabel = CreateLabelWithBase("end");

	TABBEDPREFIX << ";OPERATOR: && PART 1" << endl;
	(n->children)[0]()->Accept(this);
	TABBEDPREFIX << ";LEFT EVALUATED" << endl;
	//Is the right side false?...
	COMPARE("eax", "0")
	//... Yes. Jump to the false label
	TABBEDPREFIX << "je		" << falseLabel << endl;
	COMMENTLINE

		TABBEDPREFIX << ";OPERATOR: && PART 2" << endl;
	(n->children)[1]()->Accept(this);
	TABBEDPREFIX << ";RIGHT EVALUATED" << endl;
	//Is the left side false?...
	COMPARE("eax", "0")
	//... Yes. Jump to the false label
	TABBEDPREFIX << "je		" << falseLabel << endl;

	//End result is true
	MOVE("eax", "1")
		//And jump out after
		TABBEDPREFIX << "jmp		" << endLabel << endl;

	//End result is false
	TABBEDPREFIX << "" << falseLabel << ":" << endl;
	MOVE("eax", 0)

		//To leave, jump here
		TABBEDPREFIX << "" << endLabel << ":" << endl;

	COMMENTLINE

		return_to_parent = true;
}


void CodeGeneratingVisitor::visit(ConditionalOrExpressionNode * n){

	string trueLabel = CreateLabelWithBase("true"), endLabel = CreateLabelWithBase("end");

	//eax holds 1 or 0
	//if 1, jump to end and push 1 onto stack

	TABBEDPREFIX << ";OPERATOR: || PART 1" << endl;
	(n->children)[0]()->Accept(this);
	TABBEDPREFIX << ";LEFT EVALUATED" << endl;
	//Is the right side false?...
	COMPARE("eax", "0")
	//... Nope. Jump to the true label
	TABBEDPREFIX << "jne		" << trueLabel << endl;
	COMMENTLINE

		TABBEDPREFIX << ";OPERATOR: && PART 2" << endl;
	(n->children)[1]()->Accept(this);
	TABBEDPREFIX << ";RIGHT EVALUATED" << endl;
	//Is the left side false?...
	COMPARE("eax", "0")
	//... Nope. Jump to the true label
	TABBEDPREFIX << "jne		" << trueLabel << endl;

	//End result is false
	MOVE("eax", "0")
		TABBEDPREFIX << "jmp		" << endLabel << endl;

	//End result is true;
	TABBEDPREFIX << "" << trueLabel << ":" << endl;
	MOVE("eax", "1")

		//To leave, jump here
		TABBEDPREFIX << "" << endLabel << ":" << endl;

	COMMENTLINE

		return_to_parent = true;
}


void CodeGeneratingVisitor::visit(AndExpressionNode * n){

	string falseLabel = CreateLabelWithBase("false"), endLabel = CreateLabelWithBase("end");

	TABBEDPREFIX << ";OPERATOR: &" << endl;
	BinaryOperation_ResolveChildren((*n)[0](), (*n)[1]());

	//If the left side is false...
	COMPARE("eax", "0")
	//...then the entire thing results in false. Jump to false
	TABBEDPREFIX << "je		" << falseLabel << endl;
	//If the right side is false...
	COMPARE("ebx", "0")
	//...then the entire thing results in false. Jump to false
	TABBEDPREFIX << "je		" << falseLabel << endl;
	//The end result is true
	COMPARE("eax", "1")
		TABBEDPREFIX << "jmp		" << endLabel << endl;
	//The end result is false
	TABBEDPREFIX << "" << falseLabel << ":" << endl;
	COMPARE("eax", "0")
		//Leave through here
		TABBEDPREFIX << "" << endLabel << ":" << endl;
	COMMENTLINE

		return_to_parent = true;

}


void CodeGeneratingVisitor::visit(InclusiveOrExpressionNode * n){

	string trueLabel = CreateLabelWithBase("true"), endLabel = CreateLabelWithBase("end");

	TABBEDPREFIX << ";OPERATOR: &" << endl;
	BinaryOperation_ResolveChildren((*n)[0](), (*n)[1]());

	//If the left side is not false...
	COMPARE("eax", "0")
	//...then the entire thing results in true. Jump to true
	TABBEDPREFIX << "jne	" << trueLabel << endl;
	//If the right side is not false...
	COMPARE("ebx", "0")
	//...then the entire thing results in true. Jump to true
	TABBEDPREFIX << "jne	" << trueLabel << endl;
	//The end result is true
	MOVE("eax", "1")
		TABBEDPREFIX << "jmp	" << endLabel << endl;
	//The end result is false
	TABBEDPREFIX << "" << trueLabel << ":" << endl;
	MOVE("eax", "0")
		//Leave through here
		TABBEDPREFIX << "" << endLabel << ":" << endl;
	COMMENTLINE

		return_to_parent = true;

}

void CodeGeneratingVisitor::visit(UnaryExpressionNotPlusMinusNode * n){

	//THIS ASSUMES THAT THE BOOLEAN VALUE IS 1 FOR TRUE AND 0 FOR FALSE

	TABBEDPREFIX << ";OPERATOR: !" << endl;
	(*n)[0]()->Accept(this);
	ADD("eax", "-1")
		TABBEDPREFIX << "imul eax, -1" << endl;

	COMMENTLINE

		return_to_parent = true;
}

/*
This
*/

void CodeGeneratingVisitor::visit(PrimaryNoNewArrayNode * n){

	if (n->children.empty()) MOVE("eax", THIS << "; == 'this'")
}


/*
Variables
*/

void CodeGeneratingVisitor::visit(NameNode *n) {

	//Generate the pointer to the 'this' object
	if (n->children.empty()) {
		MOVE("eax", THIS << "; == 'this'");
		return;
	}

	//The name describes a type. Return the label
	if (n->visited_locations.empty()) {
		MOVE("eax", n->declaration_reference->label)
			return;
	}


	//First put the context into eax
	if (((ParseNode*)n->visited_locations[0])->Type() == "FieldDeclaration" && !(n->visited_locations[0]->modifier & ModifiedNode::Static))
		MOVE("eax", THIS << "; == 'this'")


		string null_reference = CreateLabelWithBase("nullreference"), success = CreateLabelWithBase("success");
	for (vector<TypedNode*>::iterator location = n->visited_locations.begin(); location != n->visited_locations.end() - 1; ++location) {
		if ((*location)->modifier & ModifiedNode::Static)
			MOVE("eax", "[eax]; The next field's static; go to class data")
		MOVE("eax", "[" << (*location)->label << " + " << (*location)->Offset() << "]; == " << (*location)->identifier)
		COMPARE("eax", "0; Is this field null?")
		TABBEDPREFIX << "je " << null_reference << endl;
	}

	TypedNode *last_location = *n->visited_locations.rbegin();
	TABBEDPREFIX << "lea ebx, [" << last_location->label << " + " << last_location->Offset() << "]" << endl;
	MOVE("eax", "[ebx]; == " << last_location->identifier)

	if (n->visited_locations.size() > 1) {
		TABBEDPREFIX << "jmp " << success << endl;
		NOPREFIX << null_reference << ":" << endl;
		THROWEXCEPTION
			NOPREFIX << success << ":" << endl;
	}
}
void CodeGeneratingVisitor::visit(MethodInvocationNode *n) {

	//Evaluate the pointer to the context of this method
	(*n)[0]()->Accept(this);
	MOVE("edx", "eax; Store the context (dereferenced to a class data) while arguments are evaluating")
		//Push whatever needs to be stored before the method starts
		int pushes = 0;
	vector<SP<ParseNode> > &method_children = n->children;
	for (vector<SP<ParseNode> >::iterator child = method_children.begin(); child != method_children.end(); ++child) {
		if ((*child)()->Type() != "Expression") continue;

		pushes += 1;
		(*child)()->Accept(this);
		PUSH("eax; Push arg " << pushes);
	}
	if (!(n->method->modifier & ModifiedNode::Static))
		PUSH("edx; Push 'this'")
	else
	PUSH("0")
	TABBEDPREFIX << "call [edx+" << n->method->Offset() << "]; == " << n->method_identifier << "()" << endl;

	//Need to pop the stack
	ADD("esp", ((pushes + 1) * 4))


		return_to_parent = true;
}

void CodeGeneratingVisitor::visit(ArrayAccessNode *n) {
	string out_of_bounds = CreateLabelWithBase("outofbounds"), in_bounds = CreateLabelWithBase("inbounds");

	(*n)[0]()->Accept(this);

	COMPARE("eax", "0; Is this array null?")
	TABBEDPREFIX << "je " << out_of_bounds << endl;
	//Put the location of the array into ecx
	PUSH("eax; Put the array location away for now");
	(*n)[1]()->Accept(this);
	POP("ecx; Recover the array location");
	COMPARE("eax", "0")
	TABBEDPREFIX << "jl\t" + out_of_bounds + "; Index was less than 0" << endl;
	//Get the length of the array
	MOVE("ebx", "[ecx+4]; Put the array length into ebx")
	COMPARE("eax", "ebx; Compare the index with the length")
	TABBEDPREFIX << "jge\t" + out_of_bounds + "; Index was beyond the array" << endl;
	TABBEDPREFIX << "jmp\t" + in_bounds << endl;
	NOPREFIX << out_of_bounds << ":" << endl;
	THROWEXCEPTION
		NOPREFIX << in_bounds << ":" << endl;

	//put the value into eax, and the value is at index of element * 4 to put into byte offset + the base address of the array
	TABBEDPREFIX << "lea ebx, [ecx + eax*4+8]; Load the effective address for the array element into ebx" << endl;
	MOVE("eax", "[ebx]")

		return_to_parent = true;
}
void CodeGeneratingVisitor::visit(FieldAccessNode *n) {

	(*n)[0]()->Accept(this);

	if (n->field) {
		TABBEDPREFIX << "lea ebx, [eax+" << n->field->Offset() << "]; Load the first address" << endl;
		MOVE("eax", "[ebx]; == " << n->field->identifier)
	}
	else {
		MOVE("eax", "[eax+8]; Get the length of this array")
	}

	return_to_parent = true;
}


/*
Literals
*/

void CodeGeneratingVisitor::visit(IntegerLiteralNode * n){
	TABBEDPREFIX << ";LITERAL:INT " << n->value << endl;
	MOVE("eax", n->value)
		COMMENTLINE
}

void CodeGeneratingVisitor::visit(CharacterLiteralNode* n){
	TABBEDPREFIX << ";LITERAL:CHAR " << n->value << endl;
	MOVE("eax", (int)n->value)
		COMMENTLINE
}

void CodeGeneratingVisitor::visit(BooleanLiteralNode* n){
	TABBEDPREFIX << ";LITERAL:BOOLEAN " << n->value << endl;
	MOVE("eax", n->value)
		COMMENTLINE
}

void CodeGeneratingVisitor::visit(NullLiteralNode* n){
	TABBEDPREFIX << ";LITERAL:NULL " << endl;
	MOVE("eax", 0)
		COMMENTLINE
}


void CodeGeneratingVisitor::BinaryOperation_ResolveChildren(ParseNode *left_child, ParseNode *right_child) {

	left_child->Accept(this);
	PUSH("eax")
		right_child->Accept(this);
	MOVE("ebx", "eax")
		POP("eax")
}

void CodeGeneratingVisitor::visit(ClassInstanceCreationExpressionNode*n) {
	// malloc into eax 
	COMMENTLINE
		TABBEDPREFIX << "; Creating Object of type " << n->type_meta.reference->identifier << endl;
	TABBEDPREFIX << "; Constructor args:" << endl;

	unsigned int num_params = 0;
	while (num_params < n->children.size()) {
		n->children[num_params++]()->Accept(this);
		TABBEDPREFIX << ";Constructor Arg" << num_params << endl;
		PUSH("eax")
	}
	return_to_parent = true;
	TABBEDPREFIX << "; Object creation and pass to constructor" << endl;
	MOVE("eax", class_sizes[n->type_meta.reference] * 4);
	TABBEDPREFIX << "call __malloc	" << endl;

	TABBEDPREFIX << "; Zero out field values:" << endl;
	for (unsigned int i = 2; i < class_sizes[n->type_meta.reference]; ++i)
		MOVE("[eax+" << i << "*4]", "0")

	//call constructor
	//dereference to object and assign first field to class label
	MOVE("ebx", n->type_meta.reference->label);
	MOVE("[eax]", "ebx\t;setting class");
	MOVE("[eax+4]", "-1; This is not an array")
	PUSH("eax");

	TABBEDPREFIX << "call	" << n->constructor->label << "\t;ebx is offset to constructor function" << endl;



	TABBEDPREFIX << "; Returning object pointer" << endl;
	POP("eax");
	TABBEDPREFIX << "; clean contructor params" << endl;
	ADD("esp", num_params * 4);
	TABBEDPREFIX << "; END OBJECT CREATION" << endl;
	COMMENTLINE

}

void CodeGeneratingVisitor::visit(ArrayCreationExpressionNode*n) {
	string length_valid = CreateLabelWithBase("lengthvalid");

	COMMENTLINE
		TABBEDPREFIX << "; Creating Array of type " << n->type_meta.category << endl;
	TABBEDPREFIX << "; Evaluate array size: " << endl;
	(*n)[0]()->Accept(this);
	COMPARE("eax", "0")
	TABBEDPREFIX << "jge " << length_valid << endl;
	THROWEXCEPTION
		NOPREFIX << length_valid << ":" << endl;
	TABBEDPREFIX << "; Calculate Array object size" << endl;
	TABBEDPREFIX << "; add class pointer and length value" << endl;
	PUSH("eax	; Save array element size");
	ADD("eax", "2");
	TABBEDPREFIX << "imul	eax,	4	; array size in bytes" << endl;
	TABBEDPREFIX << "; Allocate Array" << endl;
	TABBEDPREFIX << "call __malloc	" << endl;
	TABBEDPREFIX << "; Set Array class field to Object and length field to stored length" << endl;

	if (n->type_meta.category == TypeMeta::Reference || n->type_meta.category == TypeMeta::String) {
		MOVE("[eax]", n->type_meta.reference->label);
	}
	else {
		unsigned int type_val = 0;
		switch (n->type_meta.category) {
		case TypeMeta::Boolean: type_val = 1; break;
		case TypeMeta::Char: type_val = 2; break;
		case TypeMeta::Byte: type_val = 3; break;
		case TypeMeta::Short: type_val = 4; break;
		case TypeMeta::Int: type_val = 5; break;
		}
		MOVE("[eax]", type_val);
	}
	POP("ebx");
	MOVE("[eax+4]", "ebx");

	string start = CreateLabelWithBase("start"), done = CreateLabelWithBase("done");

	TABBEDPREFIX << "; Zero out array values" << endl;
	NOPREFIX << start << ":" << endl;
	COMPARE("ebx", "0")
	TABBEDPREFIX << "je " << done << endl;
	ADD("ebx", "-1")
		MOVE("[eax+8+ebx*4]", "0")
		TABBEDPREFIX << "jmp " << start << endl;
	NOPREFIX << done << ":" << endl;

	TABBEDPREFIX << "; END ARRAY CREATION" << endl;
	COMMENTLINE

		return_to_parent = true;
}


void CodeGeneratingVisitor::visit(LocalVariableDeclarationNode *n) {
	COMMENTLINE
		TABBEDPREFIX << "; Initializing local " << n->identifier << endl;
	(*n)["Expression"]->Accept(this);

	string error = CreateLabelWithBase("error"), success = CreateLabelWithBase("success");
	if (n->type_meta.category & TypeMeta::Array) {
		COMPARE("[eax+4]", "0; Check that the other is an array as well")
		TABBEDPREFIX << "jl " << error << endl;
	}
	if (n->type_meta.category & (TypeMeta::Reference | TypeMeta::String)) {
		MOVE("ebx", "[" << n->type_meta.reference->label << "-4]; Get the tag from the left side type")
			MOVE("ecx", "[eax]; Get the class data from this object")
			TABBEDPREFIX << "imul\tdword ebx,\tdword -4" << endl;
		COMPARE("[ecx-8+ebx]", "0")
		TABBEDPREFIX << "je " << error << endl;
	}

	TABBEDPREFIX << "jmp " << success << endl;
	NOPREFIX << error << ":" << endl;
	THROWEXCEPTION
		NOPREFIX << success << ":" << endl;
	MOVE("[" << n->label << "+" << n->Offset() << "]", "eax");

	return_to_parent = true;
}
void CodeGeneratingVisitor::visit(AssignmentNode *n) {
	COMMENTLINE
		TABBEDPREFIX << "; Assignment" << endl;
	ParentNode *thing_being_accessed = (ParentNode*)(*(ParentNode*)(*n)["LeftHandSide"])[0]();

	string error = CreateLabelWithBase("error"), success = CreateLabelWithBase("success");
	if (thing_being_accessed->Type() == "ArrayAccess") {
		ArrayAccessNode *accessn = (ArrayAccessNode*)thing_being_accessed;


		(*n)[0]()->Accept(this);
		PUSH("eax")
			PUSH("ebx")
			(*n)[1]()->Accept(this);

		switch (accessn->array_type.category ^ TypeMeta::Array) {
		case TypeMeta::Reference:
		case TypeMeta::String:
			MOVE("ebx", "[" << accessn->array_type.reference << "-4]; Get the tag from the left side type")
				MOVE("ecx", "[eax]; Get the class data for this object")
				TABBEDPREFIX << "imul\tdword ebx,\tdword -4" << endl;
			COMPARE("[ecx-8+ebx]", "0")
			TABBEDPREFIX << "je " << error << endl;
			break;
		default:
			TABBEDPREFIX << "jmp " << success << endl;
		}

		NOPREFIX << error << ":" << endl;
		THROWEXCEPTION
			NOPREFIX << success << ":" << endl;
		POP("ebx")
			ADD("esp", "4; skip over the eax we pushed")
			MOVE("[ebx]", "eax");
	}
	else {
		TypedNode *type = (TypedNode*)thing_being_accessed;
		string arraycheck = CreateLabelWithBase("arraycheck");

		(*n)[0]()->Accept(this);
		PUSH("ebx; Put the location reference away for a bit")
			MOVE("ecx", "eax")
			(*n)[1]()->Accept(this);

		switch (type->type_meta.category) {
		case TypeMeta::Reference:
		case TypeMeta::String:
			COMPARE("eax", "0")
			TABBEDPREFIX << "je " << success << endl;

			COMPARE("[eax+4]", "0")
			TABBEDPREFIX << "jge " << arraycheck << endl;

			MOVE("ebx", "[" << type->type_meta.reference->label << "-4]; Get the tage from the left side type")
				MOVE("ecx", "[eax]; Get the class data for this object")

			TABBEDPREFIX << "imul\tdword ebx,\tdword -4" << endl;
			COMPARE("[ecx-8+ebx]", "0")
			TABBEDPREFIX << "je " << error << endl;
			TABBEDPREFIX << "jmp " << success << endl;

			NOPREFIX << arraycheck << ":" << endl;
			COMPARE("[eax]", "java.lang.Object; Is this array's class Object")
			TABBEDPREFIX << "je " << success << endl;
			COMPARE("[eax]", "java.lang.Cloneable; Is this array's class Cloneable")
			TABBEDPREFIX << "je " << success << endl;
			COMPARE("[eax]", "java.io.Serializable; Is this array's class Serializable")
			TABBEDPREFIX << "je " << success << endl;

			break;
		default: break;
		}
		NOPREFIX << error << ":" << endl;
		THROWEXCEPTION
			NOPREFIX << success << ":" << endl;
		POP("ebx")
			ADD("esp", "4; skip over the eax we pushed")
			MOVE("[ebx]", "eax");
	}

	return_to_parent = true;
}


void CodeGeneratingVisitor::visit(StringLiteralNode *n) {
	ClassInstanceCreationExpressionNode cicen;
	cicen.type_meta.category = TypeMeta::String;
	cicen.type_meta.reference = TypeMeta::string_declaration;

	TypedNode tn;
	tn.identifier = "String$";

	cicen.constructor = (ConstructorDeclarationNode*)*TypeMeta::string_declaration->elements_in_scope[DeclarationNode::Method].find(&tn);

	//Build a new string object into eax
	cicen.Accept(this);

	PUSH("eax; Push that while we create a new array");

	ArrayCreationExpressionNode acen;
	acen.type_meta.category = TypeMeta::Char;
	acen.type_meta.reference = 0x0;

	unsigned int size = n->value.length();

	IntegerLiteralNode *i = new IntegerLiteralNode();
	i->value = size;

	acen.children.push_back(i);

	//Create a new character array
	acen.Accept(this);

	POP("ebx; Now we can set the new array to the pointer")
	MOVE("[ebx+4]", "eax; The char array is the first field in the String")
	MOVE("eax", "[eax]; Go to the location of element 0 in the array")

	for (unsigned int i = 0; i < size; ++i) {
		MOVE("eax", (unsigned int)n->value[i])
		ADD("eax", "4")
	}

	MOVE("eax", "ebx; Move the pointer to the new String into eax")
}